<template>
  <div :data-key="node.key" :style="{ marginLeft: `${level * 12}px` }" @contextmenu="onContextMenu">
    <n-list-item
      class="tree-node"
      :class="[className, { active: isSelected }]"
      @click="handleClick"
    >
      <!-- 普通节点 -->
      <template #prefix>
        <n-icon class="list-icon" size="22" style="margin-top: 7px;" :component="iconComponent" />
        <div v-show="false">
          <n-icon class="ni" :component="BookOutline" />
          <n-icon class="ni" :component="ChevronUp" />
        </div>
      </template>

      <div
        style="margin-left: -9px; padding-top: 5px; display: flex;"
      >
        <div
          ref="editDiv"
          class="editable-text"
          :contenteditable="node.isEditing"
          @blur="update"
          @keydown.enter.prevent="update"
        >
          {{ node.label }}
        </div>
      </div>


      <template #suffix>
        <div style="display: flex; align-items: center;">
          <n-flex style="gap:6px; align-items:center; padding-right: 5px;">
            <n-popover trigger="hover" placement="right-start">
              <template #trigger>
                <n-button text size="tiny" @click.stop="startEdit()">
                  <n-icon><Pencil /></n-icon>
                </n-button>
              </template>
              <span>编辑</span>
            </n-popover>

            <n-popover trigger="hover" placement="right-start">
              <template #trigger>
                <n-button text size="tiny" @click.stop="confirmDelete">
                  <n-icon><TrashOutline /></n-icon>
                </n-button>
              </template>
              <span>删除</span>
            </n-popover>


          </n-flex>
          <n-popover trigger="hover" placement="right-start">
            <template #trigger>
              <n-button text icon-placement="right" @click.stop="addNode(node)">
                <template #icon>
                  <NIcon size="18"><Add /></NIcon>
                </template>
              </n-button>
            </template>
            <span>添加</span>
          </n-popover>

          <!-- ✅ 动画旋转箭头 -->
          <n-icon
            size="16"
            v-if="hasChildren"
            class="arrow-icon"
            :class="{ expanded: isExpanded }"
            :component="ChevronDown"
          />
        </div>
      </template>
    </n-list-item>

    <!-- 子节点 -->
     <!-- ✅ 动画过渡 -->
    <transition name="expand">
      <draggable
        v-if="hasChildren && isExpanded"
        v-model="node.children"
        class="draggable-box"
        group="label"
        item-key="key"
        :animation="150"
        :force-fallback="true"
        :handle="'.list-icon'"
        @start="onDragStart"
        @end="onDragEnd"
        @move="onDragMove"
      >
        <template #item="{ element }">
          <TreeNode
            v-if="element"
            :node="element"
            :parent-node="node"
            :level="level + 1"
            :selected-key="selectedKey"
            @select="emitSelect"
            @insert="emitInsert"
            @delete="emitDelete"
            @update="emitUpdate"
            @load-children="emitLoad"
            @drag-end="onDragEnd"
          />
        </template>
      </draggable>
    </transition>


    <n-modal
      v-model:show="showModal"
      preset="dialog"
      title="删除"
      content="是否删除该节点？"
      positive-text="确认"
      negative-text="取消"
      @positive-click="onPositiveClick"
    />
  </div>
</template>

<script setup lang="ts">
import { ref, computed, nextTick, watch } from 'vue'
import draggable from 'vuedraggable'
import {
  NIcon,
  useMessage
} from 'naive-ui'
import {
  ChevronDown,
  ChevronUp,
  Pencil,
  Add,
  TrashOutline,
  Folder,
  FolderOpenOutline,
  BookOutline
} from '@vicons/ionicons5'
import TreeNode from './TreeNode.vue'
import { useMenuStore } from '../../stores/menuStore';
const menuStore = useMenuStore();

// 设置特殊页面的右键菜单项
const onContextMenu = (event: MouseEvent) => {
  event.preventDefault();
  event.stopPropagation()
  // 特殊页面的右键菜单项
  const specialMenuItems = [
    { id: 'refresh', text: '刷新子目录', action: () => {
      if (props.node.type === 'book') {
        emit('load-children', props.node);
      } else if (props.node.type === 'directory') {
        emit('load-children', props.parentNode);
      }
    } },
    { id: 'special-delete', text: '特殊删除', action: () => console.log('执行特殊删除') },
  ];
  menuStore.resetMenu(); // 重置当前菜单项
  menuStore.setMenu(specialMenuItems, { x: event.clientX, y: event.clientY });
};



interface TreeNodeData {
  key: string | number
  label?: string
  parentKey: string | number
  groupId: string | number
  children?: TreeNodeData[]
  type?: string
  icon?: any
  isLoaded?:boolean
  isEditing?: boolean
  pids?: Array<string | number>
}

const props = withDefaults(defineProps<{
  node?: TreeNodeData
  parentNode?: TreeNodeData
  level?: number
  selectedKey: Array<string | number>
}>(), {
  node: () => ({ key: '', parentKey: '', groupId: '', label: '', children: [] }),
  parentNode: () => ({ key: '', parentKey: '', groupId: '', label: '', children: [] }),
  level: 0
})


const emit = defineEmits(['load-children', 'select', 'insert', 'delete', 'update', 'drag-end'])

const message = useMessage()
const showModal = ref(false)
const isExpanded = ref(false)

const isSelected = computed(() => props.selectedKey.indexOf(props.node.key) >= 0)
const hasChildren = computed(() => Array.isArray(props.node.children))
const iconComponent = computed(() => props.node.icon || Folder)
const className = computed(() => (props.level === 0 ? 'level-0' : 'level-child'))
const editDiv = ref<HTMLDivElement | null>(null)

if (props.node.key === '-1') {
  startEdit();
}

function handleClick(e: MouseEvent) {
  e.stopPropagation()
  emit('select', props.node)
  if (props.node.type == "book" && props.node.children) {
    if (!isExpanded.value) {      
      return new Promise(resolve => {
        emit('load-children', props.node);
        // 父组件加载完成后要调用子组件一个方法或者通过props改变触发resolve
        // 这里示例简单，实际父组件加载完成后可以通过事件通知子组件
        // 或使用watch监听 node.children 变化，然后resolve
        const unwatch = watch(
          () => props.node.isLoaded,
          (loaded) => {
            if (loaded) {
              console.log("node1 ", props.node);
              unwatch();
              resolve(props.node);
              props.node.isLoaded = false;
              if (props.node.children) {
                isExpanded.value = !isExpanded.value
              }
            }
          }
        );
      });
    }
  }
  if (hasChildren.value) {
    isExpanded.value = !isExpanded.value
  }
}

function emitSelect(node: TreeNodeData) {
  emit('select', node)
}

function emitLoad(node: TreeNodeData) {
  if (node.children) {
    //emit('load-children', node)
    // return new Promise(resolve => {
    //   emit('load-children', node);
    //   // 父组件加载完成后要调用子组件一个方法或者通过props改变触发resolve
    //   // 这里示例简单，实际父组件加载完成后可以通过事件通知子组件
    //   // 或使用watch监听 node.children 变化，然后resolve
    //   const unwatch = watch(
    //     () => node.isLoaded,
    //     (loaded) => {
    //       if (loaded) {
    //         unwatch();
    //         resolve(node);
    //         node.isLoaded = false;
    //       }
    //     }
    //   );
    // });
  }
}

function emitDelete(node: TreeNodeData) {
  emit('delete', node)
}

function emitUpdate(node: TreeNodeData) {
  emit('update', node)
}

function emitInsert(node: TreeNodeData) {
  emit('insert', node)
}

function startEdit() {
  props.node.isEditing = true
  nextTick(() => {
    if (editDiv.value) {
      editDiv.value.focus()
      const range = document.createRange()
      const sel = window.getSelection()
      range.selectNodeContents(editDiv.value)
      range.collapse(false)
      sel?.removeAllRanges()
      sel?.addRange(range)
    }
  })
}


function update() {
  if (!editDiv.value) {
    return
  }
  const newText = editDiv.value.innerText.trim()
  if (props.node.key === '-1' && !newText && props.parentNode?.children) {
    const index = props.parentNode.children.findIndex(child => child.key === props.node.key);
    console.log(index)
    if (index !== -1) {
      props.parentNode.children.splice(index, 1); // 删除该节点
    }
    return
  } else {
    if (!newText) {
      message.warning('名称不能为空')
      return
    }
  }
  props.node.label = newText;
  props.node.isEditing = false
  console.log(props.node);
  
  if (props.node.key === '-1') {
    emit('insert', props.node)
  } else {
    emit('update', props.node)
  }
  
}

function confirmDelete() {
  showModal.value = true
}

function onPositiveClick() {
  if (props.parentNode?.children) {
    const index = props.parentNode.children.findIndex(child => child.key === props.node.key);
    console.log(index)
    if (index !== -1) {
      props.parentNode.children.splice(index, 1); // 删除该节点
      console.log("parent ", props.parentNode)
    }
  }
  emit('delete', props.node)
}

async function addNode(node?: TreeNodeData) {
  if (node?.type === 'book' && !isExpanded.value) {
    return new Promise(resolve => {
      emit('load-children', node);
      // 父组件加载完成后要调用子组件一个方法或者通过props改变触发resolve
      // 这里示例简单，实际父组件加载完成后可以通过事件通知子组件
      // 或使用watch监听 node.children 变化，然后resolve
      const unwatch = watch(
        () => props.node.isLoaded,
        (loaded) => {
          if (loaded) {
            unwatch();
            resolve(node);
            props.node.isLoaded = false;
            if (!props.node.children) {
              props.node.children = [];
            }
            props.node.children.push({
                key: "-1",
                children: [],
                groupId: props.node.groupId,
                parentKey: props.node.key,
                type: "directory",
                icon: FolderOpenOutline
            })
            if (hasChildren.value) {
              isExpanded.value = true;
            }
          }
        }
      );
    });
  }
  if (node && node.children) {
    node.children.push({
        key: "-1",
        children: [],
        groupId: node.groupId,
        parentKey: node.key,
        type: "directory",
        icon: FolderOpenOutline
    })
  } else {
    message.error("数据错误！")
  }
  if (hasChildren.value) {
    isExpanded.value = true;
  }
}


// 拖拽开始
function onDragStart(evt: any) {
  console.log(evt);
  
  message.info('只能同级节点之间拖拽排序')
}


// 拖拽结束时自动展开父节点
function onDragEnd(evt: any) {
  console.log('拖拽结束', props.node);
  // 如果目标父节点没有展开，自动展开
  if (!isExpanded.value && !props.node.isEditing) {
    isExpanded.value = true;  // 展开父节点
  }
  if (!evt || !props.node?.children) return;
  emit('drag-end', { parentKey: props.node.key, children: props.node.children })
}


function onDragMove(evt: any){
  console.log(evt.to);
  console.log(evt.from);
}

</script>



<style scoped>
.tree-node {
  user-select: none;
  display: flex;
  align-items: flex-start;
  cursor: grab;
  transition: background-color 0.25s;
}
.tree-node.active {
  color: #18a058;
  font-weight: 600;
}
.node-content {
  margin-left: -9px;
  padding-top: 5px;
  display: flex;
  align-items: center;
}
.edit-input {
  height: 27px;
  width: 100%;
  font-size: 14px;
  background-color: rgba(255, 255, 255, 0.3);
  margin-left: -10px;
}
.suffix-actions {
  display: flex;
  align-items: center;
}
.arrow-icon {
  margin-left: 8px;
  transition: transform 0.25s ease;
}
.arrow-icon.expanded {
  transform: rotate(180deg);
}

/* ✅ 展开收起动画 */
.expand-enter-active,
.expand-leave-active {
  transition: all 0.25s ease;
  overflow: hidden;
}
.expand-enter-from,
.expand-leave-to {
  opacity: 0;
  max-height: 0;
}
.expand-enter-to,
.expand-leave-from {
  opacity: 1;
  max-height: 600px;
}

.editable-text {
  max-width: 180px;  /* 最大宽度 */
  padding: 4px 8px;  /* 内边距 */
  border-radius: 4px; /* 边角圆滑 */
  white-space: nowrap; /* 防止文本换行 */
  overflow: hidden;    /* 超出部分隐藏 */
  text-overflow: ellipsis;  /* 超出部分显示省略号 */
  transition: border-color 0.3s ease, box-shadow 0.3s ease;  /* 添加过渡效果 */
}

.editable-text.editing {
  border: 1px solid #6c9ef9; /* 修改边框颜色 */
  background-color: rgba(108, 158, 249, 0.1); /* 轻微背景色 */
  outline: none;  /* 去除默认的焦点外框 */
  cursor: text;   /* 显示文本编辑光标 */
  min-width: 100px;
  box-shadow: 0 0 5px rgba(108, 158, 249, 0.3); /* 添加阴影效果 */
}

/* 鼠标悬停时改变框的颜色 */
.editable-text.editing:hover {
  border-color: #3498db; /* 鼠标悬停时边框颜色变化 */
  box-shadow: 0 0 8px rgba(52, 152, 219, 0.3); /* 增加悬停时阴影效果 */
}
</style>
